package edu.hawaii.stack;

import java.util.ArrayList;
import java.io.Serializable;

/**
 * Implements the stack abstract data type expeditiously. This main class, in addition to providing
 * the fundamental operations associated with a Stack ADT, also provides methods to retrieve the
 * current version number associated with this release from the manifest file, and the main() method
 * invoked when using 'java -jar stack.jar'. This main method simply returns the current version
 * number.
 * 
 * @author Philip M. Johnson
 * @version $Id: Stack.java,v 1.1.1.1 2005/02/02 02:17:52 johnson Exp $
 */
public class Stack implements Serializable {

  /**
   * Holds the elements.
   * Visibility is protected to allow subclass access to internal representation.
   */
  protected ArrayList elements = new ArrayList();


  /**
   * Pushes obj onto the stack.
   *
   * @param obj Any object.
   */
  public void push(Object obj) {
    this.elements.add(obj);
  }

  /**
   * Returns the last object pushed onto the stack and removes
   * that object from the stack.
   *
   * @return The last object pushed.
   * @throws EmptyStackException If the stack was empty at the time of the pop.
   */
  public Object pop() throws EmptyStackException {
    try {
      Object obj = this.elements.get(elements.size() - 1);
      elements.remove(elements.size() - 1);
      return obj;
    }
    catch (Exception e) {
      throw new EmptyStackException(e);
    }
  }


  /**
   * Returns the last object pushed onto the stack without removing it.
   *
   * @return The last object pushed.
   * @throws EmptyStackException If the stack was empty at the time of the top.
   */
  public Object top() throws EmptyStackException {
    try {
      Object obj = this.elements.get(elements.size() - 1);
      return obj;
    }
    catch (Exception e) {
      throw new EmptyStackException(e);
    }
  }


  /**
   * Returns a shallow copy of the current stack as an array.
   *
   * @return An array containing the elements of the stack.
   */
  public Object[] toArray() {
    ArrayList stackCopy = (ArrayList) elements.clone();
    return this.elements.toArray();
  }

  /**
   * Return the current version number if found in the manifest file, or "unknown".
   *
   * @return The version number, or "unknown" if could not be determined.
   */
  public static String getVersion() {
    String version = "";
    try {
      Package thisPackage = Class.forName("edu.hawaii.stack.Stack").getPackage();
      version = thisPackage.getSpecificationVersion(); 
    } 
    catch (Exception e) {
      // Do nothing.
    }
  return ((version == null)) ? "unknown" : version;
  }

  /**
   * Provides a readable representation of the stack.
   *
   * @return The stack as a string.
   */
  public String toString() {
    return "[Stack " + this.elements + "]";
  }

  /**
   * The main method, which just prints out the release information.
   *
   * @param args No args used.
   */
  public static void main(String[] args) {
    System.out.println("Stack Release: " + Stack.getVersion());
  }
}
